﻿// <copyright file="XsdTypeConverter.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-04-12</date>
// <summary> XSD type to the CLR type Converter.</summary>
// <revision>$Id$</revision>

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace OpenWPFChart.Helpers.XmlItemDataReader
{
	/// <summary>
	///  XML type to the CLR type Converter interface.
	/// </summary>
	public interface IXmlTypeConverter
	{
		/// <summary>
		/// Converts the value of XML type to the specified target type.
		/// </summary>
		/// <param name="targetType">Target Type.</param>
		/// <param name="xmlTypeString">The XML type string.</param>
		/// <param name="value">The value conforming to <paramref name="xmlTypeString"/>.</param>
		/// <returns>Value of <paramref name="targetType"/> type or <c>null</c>.</returns>
		object Convert(Type targetType, string xmlTypeString, string value);
	}

	/// <summary>
	///  XML type to the CLR type default Converter implementation.
	/// </summary>
	public class XmlTypeConverter : IXmlTypeConverter
	{
		#region IXsdTypeConverter Members
		/// <summary>
		/// Converts the value of XML type to the specified target type.
		/// </summary>
		/// <param name="targetType">Target Type.</param>
		/// <param name="xmlTypeString">The XML type string.</param>
		/// <param name="value">The value conforming to <paramref name="xmlTypeString"/>.</param>
		/// <returns>Value of <paramref name="targetType"/> type or <c>null</c>.</returns>
		/// <exception cref="System.InvalidCastException"/>
		public object Convert(Type targetType, string xmlTypeString, string value)
		{
			switch (xmlTypeString)
			{
				case "boolean": // Boolean 
					return ConvertBoolean(value, targetType);
				case "byte": // SByte
					return ConvertSByte(value, targetType);
				case "unsignedByte": // Byte
					return ConvertByte(value, targetType);
				case "short": // Int16
					return ConvertShort(value, targetType);
				case "unsignedShort": // UInt16
					return ConvertUShort(value, targetType);
				case "int": // Int32
					return ConvertInt(value, targetType);
				case "unsignedInt": // UInt32
					return ConvertUInt(value, targetType);
				case "long": // Int64
					return ConvertLong(value, targetType);
				case "unsignedLong": // UInt64
					return ConvertULong(value, targetType);
				case "decimal": // Decimal
				case "integer": // Decimal
				case "positiveInteger": // Decimal
				case "nonPositiveInteger": // Decimal
				case "negativeInteger": // Decimal
				case "nonNegativeInteger": // Decimal
					return ConvertDecimal(value, targetType);
				case "float": // Single
					return ConvertFloat(value, targetType);
				case "double": // Double
					return ConvertDouble(value, targetType);
				case "base64Binary": // Byte[]
					return ConvertBase64Binary(value, targetType);
				case "hexBinary": // Byte[]
					return ConvertHexBinary(value, targetType);
				case "date": // DateTime
					return ConvertDate(value, targetType);
				case "dateTime": // DateTime
					return ConvertDateTime(value, targetType);
				case "gDay": // DateTime
					return ConvertDay(value, targetType);
				case "gMonth": // DateTime
					return ConvertMonth(value, targetType);
				case "gMonthDay": // DateTime
					return ConvertMonthDay(value, targetType);
				case "gYear": // DateTime
					return ConvertYear(value, targetType);
				case "gYearMonth": // DateTime
					return ConvertYearMonth(value, targetType);
				case "dayTimeDuration": // xdt:TimeSpan
				case "yearMonthDuration": // xdt:TimeSpan
					// TODO Not Implemented
					throw new NotImplementedException();
				case "duration":
					return ConvertDuration(value, targetType);
				case "time": // DateTime
					return ConvertTime(value, targetType);
				case "anyURI": // Uri
					return ConvertUri(value, targetType);
				case "anySimpleType": // String
				case "string": // String
				case "normalizedString": // String
				case "token": // String
				case "ENTITY": // String
				case "ID": // String
				case "IDREF": // String
				case "language": // String
				case "Name": // String
				case "NCName": // String
				case "NMTOKEN": // String
					return ConvertToString(value, targetType);
				case "ENTITIES": // String[]
				case "IDREFS": //  String[]
				case "NMTOKENS": // String[]
					return ConvertToStringArray(value, targetType);
				case "NOTATION": // XmlQualifiedName
				case "QName": // XmlQualifiedName
					return new XmlQualifiedName(value);
				case "untypedAtomic": // xdt:String
				case "anyAtomicType": // xdt:Object
					// TODO Not Implemented
					throw new NotImplementedException();
				default:
					return targetType == null ? null : System.Convert.ChangeType(value, targetType);
			};
		}
		#endregion IXsdTypeConverter Members

		/// <summary>
		/// Converts xsd:boolean type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:boolean string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertBoolean(string value, Type targetType)
		{
			bool b = XmlConvert.ToBoolean(value);
			if (targetType == null || targetType == typeof(bool) || targetType == typeof(object))
				return b;
			else if (targetType == typeof(string))
				return b.ToString();
			else
				return System.Convert.ChangeType(b, targetType);
		}

		/// <summary>
		/// Converts xsd:byte type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:byte string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertSByte(string value, Type targetType)
		{
			SByte x = XmlConvert.ToSByte(value);
			if (targetType == null || targetType == typeof(SByte) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:unsignedByte type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:unsignedByte string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertByte(string value, Type targetType)
		{
			Byte x = XmlConvert.ToByte(value);
			if (targetType == null || targetType == typeof(Byte) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:short type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:short string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertShort(string value, Type targetType)
		{
			Int16 x = XmlConvert.ToInt16(value);
			if (targetType == null || targetType == typeof(Int16) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:unsignedShort type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:unsignedShort string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertUShort(string value, Type targetType)
		{
			UInt16 x = XmlConvert.ToUInt16(value);
			if (targetType == null || targetType == typeof(UInt16) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:int type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:int string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertInt(string value, Type targetType)
		{
			Int32 x = XmlConvert.ToInt32(value);
			if (targetType == null || targetType == typeof(Int32) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:unsignedInt type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:unsignedInt string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertUInt(string value, Type targetType)
		{
			UInt32 x = XmlConvert.ToUInt32(value);
			if (targetType == null || targetType == typeof(UInt32) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:long type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:long string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertLong(string value, Type targetType)
		{
			Int64 x = XmlConvert.ToInt64(value);
			if (targetType == null || targetType == typeof(Int64) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:unsignedLong type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:unsignedLong string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertULong(string value, Type targetType)
		{
			UInt64 x = XmlConvert.ToUInt64(value);
			if (targetType == null || targetType == typeof(UInt64) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:decimal type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:decimal string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertDecimal(string value, Type targetType)
		{
			Decimal x = XmlConvert.ToDecimal(value);
			if (targetType == null || targetType == typeof(Decimal) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:float type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:float string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertFloat(string value, Type targetType)
		{
			Single x = XmlConvert.ToSingle(value);
			if (targetType == null || targetType == typeof(Single) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:double type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:double string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertDouble(string value, Type targetType)
		{
			Double x = XmlConvert.ToDouble(value);
			if (targetType == null || targetType == typeof(Double) || targetType == typeof(object))
				return x;
			else if (targetType == typeof(string))
				return x.ToString();
			else
				return System.Convert.ChangeType(x, targetType);
		}

		/// <summary>
		/// Converts xsd:base64Binary type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:base64Binary string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertBase64Binary(string value, Type targetType)
		{
			List<byte> bytes = new List<byte>();
			string xml = @"<a>" + value + @"</a>";
			using (StringReader sr = new StringReader(xml))
			using (XmlReader rdr = XmlReader.Create(sr))
			{
				rdr.MoveToContent();
				byte[] buf = new byte[1024];
				int n = 0;
				do
				{
					n = rdr.ReadElementContentAsBase64(buf, 0, 1024);
					for (int i = 0; i < n; i++)
					{
						bytes.Add(buf[i]);
					}
				} while (n > 0);
			}
			if (targetType == null || targetType == typeof(byte[]) || targetType == typeof(object))
				return bytes.ToArray();
			else if (targetType == typeof(string))
				return bytes.ToArray().ToString();
			else
				return System.Convert.ChangeType(bytes.ToArray(), targetType);
		}

		/// <summary>
		/// Converts xsd:hexBinary type to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:hexBinary string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertHexBinary(string value, Type targetType)
		{
			List<byte> bytes = new List<byte>();
			string xml = @"<a>" + value + @"</a>";
			using (StringReader sr = new StringReader(xml))
			using (XmlReader rdr = XmlReader.Create(sr))
			{
				rdr.MoveToContent();
				byte[] buf = new byte[1024];
				int n = 0;
				do
				{
					n = rdr.ReadElementContentAsBinHex(buf, 0, 1024);
					for (int i = 0; i < n; i++)
					{
						bytes.Add(buf[i]);
					}
				} while (n > 0);
			}
			if (targetType == null || targetType == typeof(byte[]) || targetType == typeof(object))
				return bytes.ToArray();
			else if (targetType == typeof(string))
				return bytes.ToArray().ToString();
			else
				return System.Convert.ChangeType(bytes.ToArray(), targetType);
		}

		/// <summary>
		/// Converts xsd:date to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:date string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#date"/>
		///</remarks>
		static object ConvertDate(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "yyyy-MM-dd", "yyyy-MM-ddZ", "yyyy-MM-ddzzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:dateTime to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:dateTime string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#dateTime"/>
		///</remarks>
		static object ConvertDateTime(string value, Type targetType)
		{
			string[] formats = new string[] { 
				"yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHH:mm:ss.f", "yyyy-MM-ddTHH:mm:ss.ff" 
				, "yyyy-MM-ddTHH:mm:ss.fff", "yyyy-MM-ddTHH:mm:ss.ffff", "yyyy-MM-ddTHH:mm:ss.fffff" 
				, "yyyy-MM-ddTHH:mm:ss.ffffff", "yyyy-MM-ddTHH:mm:ss.fffffff", "yyyy-MM-ddTHH:mm:ssZ" 
				, "yyyy-MM-ddTHH:mm:ss.fZ", "yyyy-MM-ddTHH:mm:ss.ffZ", "yyyy-MM-ddTHH:mm:ss.fffZ" 
				, "yyyy-MM-ddTHH:mm:ss.ffffZ", "yyyy-MM-ddTHH:mm:ss.fffffZ", "yyyy-MM-ddTHH:mm:ss.ffffffZ" 
				, "yyyy-MM-ddTHH:mm:ss.fffffffZ", "yyyy-MM-ddTHH:mm:sszzzzzz", "yyyy-MM-ddTHH:mm:ss.fzzzzzz" 
				, "yyyy-MM-ddTHH:mm:ss.ffzzzzzz", "yyyy-MM-ddTHH:mm:ss.fffzzzzzz", "yyyy-MM-ddTHH:mm:ss.ffffzzzzzz" 
				, "yyyy-MM-ddTHH:mm:ss.fffffzzzzzz", "yyyy-MM-ddTHH:mm:ss.ffffffzzzzzz", "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz" 
			};
			DateTime dt = XmlConvert.ToDateTime(value, formats);
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:gDay to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:gDay string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// [Definition:]  gDay represents whole days within an arbitrary month—days that recur 
		/// at the same point in each (Gregorian) month.
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#gDay"/>
		///</remarks>
		static object ConvertDay(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "--dd--", "--ddZ", "--ddzzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else if (IsNumeric(targetType))
				return System.Convert.ChangeType(value.Substring(2, 2), targetType);
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:gMonth to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:gMonth string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		/// <remarks>
		/// gMonth represents whole (Gregorian) months within an arbitrary year—months that recur at 
		/// the same point in each year.
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#gMonth"/>
		/// see http://www.gnu.org/projects/dotgnu/pnetlib-doc/System/Xml/XmlConvert.html#XmlConvert.ToDateTime%28System.String%2C%20System.String%29%20Method
		/// </remarks>
		static object ConvertMonth(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "--MM--", "--MM--Z", "--MM--zzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else if (IsNumeric(targetType))
				return System.Convert.ChangeType(value.Substring(2, 2), targetType);
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:gYear to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:gYear string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// gYear represents Gregorian calendar years.
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#gYear"/>
		///</remarks>
		static object ConvertYear(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "yyyy", "yyyyZ", "yyyyzzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else if (IsNumeric(targetType))
				return System.Convert.ChangeType(value.Substring(0, 4), targetType);
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:time to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:time string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#time"/>
		/// time represents instants of time that recur at the same point in each calendar day, 
		/// or that occur in some arbitrary calendar day.
		///</remarks>
		static object ConvertTime(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] {
					"HH:mm:ss", "HH:mm:ss.f", "HH:mm:ss.ff", "HH:mm:ss.fff", "HH:mm:ss.ffff"
					, "HH:mm:ss.fffff", "HH:mm:ss.ffffff", "HH:mm:ss.fffffff", "HH:mm:ssZ"
					, "HH:mm:ss.fZ", "HH:mm:ss.ffZ", "HH:mm:ss.fffZ", "HH:mm:ss.ffffZ" 
					, "HH:mm:ss.fffffZ", "HH:mm:ss.ffffffZ", "HH:mm:ss.fffffffZ", "HH:mm:sszzzzzz" 
					, "HH:mm:ss.fzzzzzz", "HH:mm:ss.ffzzzzzz", "HH:mm:ss.fffzzzzzz", "HH:mm:ss.ffffzzzzzz" 
					, "HH:mm:ss.fffffzzzzzz", "HH:mm:ss.ffffffzzzzzz", "HH:mm:ss.fffffffzzzzzz" 
				});
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			//else if (targetType == typeof(TimeSpan))
			//{
			//    int z = value.IndexOf('Z');
			//    int plus = value.IndexOf('+', 1);
			//    int minus = value.IndexOf('-', 1);
			//    int end = Math.Max(z, Math.Max(plus, minus));
			//    string hhmmss = null;
			//    if (end > 0)
			//        hhmmss = value.Substring(0, end);
			//    else
			//        hhmmss = value;
			//    TimeSpan ts = TimeSpan.Parse(hhmmss);
			//    if (plus > 0 || minus > 0)
			//    {
			//        string strTz = value.Substring(Math.Max(plus, minus) + 1);
			//        int colon = strTz.IndexOf(':');
			//        string strH = strTz.Substring(0, colon);
			//        string strM = strTz.Substring(colon + 1);
			//        int hh = int.Parse(strH);
			//        int mm = int.Parse(strM);
			//        TimeSpan tz = new TimeSpan(hh, mm, 0);
			//        if (plus > 0)
			//            ts += tz;
			//        else
			//            ts -= tz;
			//    }
			//    return ts;
			//}
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:gYearMonth to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:gYearMonth string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// gYearMonth represents specific whole Gregorian months in specific Gregorian years.
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#gYearMonth"/>
		///</remarks>
		static object ConvertYearMonth(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "yyyy-MM", "yyyy-MMZ", "yyyy-MMzzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			else if (IsNumeric(targetType))
			{ // Numeric types.
				string ym = value.Substring(0, 7);
				int defis = ym.IndexOf('-');
				string strY = ym.Substring(0, defis);
				string strM = ym.Substring(defis + 1);
				int y = int.Parse(strY);
				int m = int.Parse(strM);
				return System.Convert.ChangeType(y * 12 + m, targetType);
			}
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Determines whether the specified target type is numeric.
		/// </summary>
		/// <param name="targetType">Type of the target.</param>
		/// <returns>
		/// 	<c>true</c> if the specified target type is numeric; otherwise, <c>false</c>.
		/// </returns>
		static bool IsNumeric(Type targetType)
		{
			if (targetType == typeof(System.Int16) || targetType == typeof(System.Int32)
				|| targetType == typeof(System.Int64) || targetType == typeof(System.Byte)
				|| targetType == typeof(System.Double) || targetType == typeof(System.Single)
				|| targetType == typeof(System.Decimal))
				return true;
			return false;
		}

		/// <summary>
		/// Converts xsd:gMonthDay to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:gMonthDay string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// gMonthDay represents whole calendar days that recur at the same point in each calendar 
		/// year, or that occur in some arbitrary calendar year.  (Obviously, days beyond 28 cannot 
		/// occur in all Februaries; 29 is nonetheless permitted.).
		/// <para>The ·day· value must be no more than 30 if ·month· is one of 4, 6, 9, or 11, and 
		/// no more than 29 if ·month· is 2.</para>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#gMonthDay"/>
		///</remarks>
		static object ConvertMonthDay(string value, Type targetType)
		{
			DateTime dt = XmlConvert.ToDateTime(value, new string[] { "--MM-dd", "--MM-ddZ", "--MM-ddzzzzzz" });
			if (targetType == null || targetType == typeof(DateTime) || targetType == typeof(object))
				return dt;
			else if (targetType == typeof(string))
				return dt.ToString();
			if (IsNumeric(targetType))
			{ // Numeric types.
				value = value.Substring(2, 5);
				int defis = value.IndexOf('-');
				string strM = value.Substring(0, defis);
				string strD = value.Substring(defis + 1);
				int m = int.Parse(strM);
				int d = int.Parse(strD);
				int monthDays = 0;
				for (int i = 0; i < m - 1; i++)
				{
					switch (i)
					{
						case 0:
							monthDays += 31;
							break;
						case 1:
							monthDays += 28;
							break;
						default:
							monthDays += 30;
							break;
					}
				}
				return System.Convert.ChangeType(monthDays + d, targetType);
			}
			else
				return System.Convert.ChangeType(dt, targetType);
		}

		/// <summary>
		/// Converts xsd:duration to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:duration string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// [Definition:]  duration is a datatype that represents durations of time.
		/// <para>The lexical representations of duration are more or less based on the pattern: 
		/// PnYnMnDTnHnMnS</para>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#duration"/>
		///</remarks>
		static object ConvertDuration(string value, Type targetType)
		{
			TimeSpan ts = XmlConvert.ToTimeSpan(value);
			if (targetType == null || targetType == typeof(TimeSpan) || targetType == typeof(object))
				return ts;
			else if (targetType == typeof(string))
				return ts.ToString();
			else
				return System.Convert.ChangeType(ts, targetType);
		}

		/// <summary>
		/// Converts xsd:anyURI to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">The xsd:anyURI string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		///<remarks>
		/// <see cref="http://www.w3.org/TR/xmlschema11-2/#anyURI"/>
		///</remarks>
		static object ConvertUri(string value, Type targetType)
		{
			// TODO Not implemented
			throw new NotImplementedException();
			//if (targetType == null || targetType == typeof(Uri) || targetType == typeof(object))
			//    return XmlConvert.ToUri(value);
			//else if (targetType == typeof(string))
			//    return ts.ToString();
			//else
			//    return System.Convert.ChangeType(value, targetType);
		}

		/// <summary>
		/// Converts some xsd types to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">Some xsd type string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertToString(string value, Type targetType)
		{
			if (targetType == null || targetType == typeof(string) || targetType == typeof(object))
				return value;
			else
				return null;
		}

		/// <summary>
		/// Converts some xsd types to the <paramref name="targetType"/>.
		/// </summary>
		/// <param name="value">Some xsd type string value.</param>
		/// <param name="targetType">Target type.</param>
		/// <returns></returns>
		static object ConvertToStringArray(string value, Type targetType)
		{
			if (targetType == null || targetType == typeof(string[]) || targetType == typeof(object))
				return value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
			else
				return null;
		}
	}
}
